package ar.com.mobile.persistence.container;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Observable;
import java.util.Observer;
import java.util.Properties;

public class Property extends Observable implements Observer {
	/**
	 * Ruta del archivo de propiedades
	 */
	private String path = null;
	/**
	 * Propiedades que vamos a utilizar para la conexion a la BBDD
	 */
	private Properties properties = new Properties();
	/**
	 * Thread que revisa (en un cierto intervalo de tiempo) si el archivo de
	 * properties cambia
	 */
	private PropertyService thread = null;
	/**
	 * Flag utilizado como un psedo semaforo, ya que su finalidad es restringir a #getProperties 
	 * si se puede obtener las propiedades o no 
	 */
	private volatile boolean lock = false;

	/**
	 * Realiza la construccion del archivo de propiedades para la conexion de hibernate
	 * @param path Ruta del archivo de propiedades
	 * @throws FileNotFoundException No existe el archivo o es un directorio en vez de un archivo o existe alguna otra razon por la cual no puede leerse el archivo
	 * @throws IOException Ha ocurrido un error al momento de leer el archivo
	 */
	public Property(String path, boolean verificar)
			throws FileNotFoundException, IOException {
		if (path == null || path.isEmpty())
			new IllegalArgumentException("La ruta del archivo esta vacia");

		this.path = path;
		File f = new File(path);

		this.properties.load(new FileInputStream(f));

		if (verificar) {
			this.thread = new PropertyService(f.lastModified(), path);
			this.thread.addObserver(this);
		}
	}

	/**
	 * Realiza la construccion del archivo de propiedades para la conexion de hibernate
	 * @param path Ruta del archivo de propiedades
	 * @param verificar Indica si debe ser revisado cada cierta cantidad de tiempo o no 
	 * @param initialDelay Tiempo, en segundos, que debe revisarse el archivo por primera vez
	 * @param delay Intervalo, en segundos, que debe revisarse el archivo a verificar si se hay producido cambios 
	 * @throws FileNotFoundException No existe el archivo o es un directorio en vez de un archivo o existe alguna otra razon por la cual no puede leerse el archivo
	 * @throws IOException Ha ocurrido un error al momento de leer el archivo
	 */
	public Property(String path, boolean verificar, long initialDelay,
			long delay) throws FileNotFoundException, IOException {
		if (path == null || path.isEmpty())
			new IllegalArgumentException("La ruta del archivo esta vacia");

		this.path = path;
		File f = new File(path);

		this.properties.load(new FileInputStream(f));

		if (verificar) {
			if (initialDelay < 1)
				throw new IllegalArgumentException("El tiempo a verificar el archivo por primera vez, no debe ser menor o igual a cero");
			
			if (delay < 1)
				throw new IllegalArgumentException("El intervalo a verificar el archivo por primera vez, no debe ser menor o igual a cero");			
			
			this.thread = new PropertyService(f.lastModified(), path, initialDelay, delay);
			this.thread.addObserver(this);
		}
	}

	@Override
	public void update(Observable o, Object arg) {
		lock = true;
		try {
			try {
				this.properties.load(new FileInputStream(this.path));
			} catch (FileNotFoundException e) {
				throw new RuntimeException("El archivo no existe o es un directorio o no puede leerse");
			} catch (IOException e) {
				throw new RuntimeException("Ocurrio un error al querer leer el stream del archivo");
			}
			setChanged();
			notifyObservers();
		} finally {
			lock = false;
		}
	}

	/**
	 * Propiedades que vamos a utilizar para la conexion a la BBDD
	 * @return Propiedades que vamos a utilizar para la conexion a la BBDD
	 */
	public Properties getProperties() {
		while(lock);
		return properties;
	}
}
